package com.omega.encryptedsql.registry;/**
 * @description: TODO 
 * @author omega
 * @date 2025/7/11 
 */
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.omega.encryptedsql.annotation.SensitiveField;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 实体字段注册表
 */
@Component
public class EntityFieldRegistry {
    // 缓存实体类字段信息：类 -> (字段名 -> 字段元数据)
    private final Map<Class<?>, Map<String, FieldMeta>> fieldCache = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        // 可以在这里预加载常用实体类
    }

    /**
     * 注册实体类及其字段
     */
    public void registerEntity(Class<?> entityClass) {
        if (fieldCache.containsKey(entityClass)) {
            return;
        }

        Map<String, FieldMeta> fieldMap = new HashMap<>();
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);

        if (tableInfo != null) {
            // 处理主键字段
            String keyProperty = tableInfo.getKeyProperty();
            if (keyProperty != null) {
                Field field = ReflectionUtils.findField(tableInfo.getEntityType(), keyProperty);
                if (field != null) {
                    fieldMap.put(field.getName(), createFieldMeta(field));
                }
            }

            // 处理普通字段
            for (TableFieldInfo fieldInfo : tableInfo.getFieldList()) {
                Field field = fieldInfo.getField();
                fieldMap.put(field.getName(), createFieldMeta(field));
            }
        } else {
            // 非MyBatis-Plus实体类，使用反射获取字段
            Class<?> current = entityClass;
            while (current != null) {
                for (Field field : current.getDeclaredFields()) {
                    if (field.isAnnotationPresent(SensitiveField.class)) {
                        fieldMap.put(field.getName(), createFieldMeta(field));
                    }
                }
                current = current.getSuperclass();
            }
        }

        fieldCache.put(entityClass, fieldMap);
    }

    /**
     * 获取字段元数据
     */
    public FieldMeta getFieldMeta(Class<?> entityClass, String fieldName) {
        Map<String, FieldMeta> fieldMap = fieldCache.get(entityClass);
        if (fieldMap == null) {
            registerEntity(entityClass);
            fieldMap = fieldCache.get(entityClass);
        }
        return fieldMap != null ? fieldMap.get(fieldName) : null;
    }

    private FieldMeta createFieldMeta(Field field) {
        SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
        TableField tableField = field.getAnnotation(TableField.class);

        return new FieldMeta(
                field,
                sensitiveField != null && sensitiveField.enabled(),
                sensitiveField != null ? sensitiveField.keyId() : "default",
                tableField != null ? tableField.value() : field.getName()
        );
    }

    public Map<Class<?>, Map<String, FieldMeta>> getFieldCache() {
        return this.fieldCache;
    }

    public static class FieldMeta {
        private final Field field;
        private final boolean sensitive;
        private final String keyId;
        private final String columnName;

        public FieldMeta(Field field, boolean sensitive, String keyId, String columnName) {
            this.field = field;
            this.sensitive = sensitive;
            this.keyId = keyId;
            this.columnName = columnName;
        }

        // Getters

        public Field getField() {
            return field;
        }

        public boolean isSensitive() {
            return sensitive;
        }

        public String getKeyId() {
            return keyId;
        }

        public String getColumnName() {
            return columnName;
        }
    }
}
